#!/usr/bin/env perl

# Copyright (c) 2011, Ryan M. Lefever
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
#     * Redistributions of source code must retain the above copyright
#       notice, this list of conditions and the following disclaimer.
#     * Redistributions in binary form must reproduce the above
#       copyright notice, this list of conditions and the following
#       disclaimer in the documentation and/or other materials provided
#       with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

# enable perl's safety info
use strict;
use warnings;
use File::Basename;

# Global variables
my @inputFiles;
my @fromStrs;
my @toStrs;
my $debug = 1;

if($#ARGV == 0 && ($ARGV[0] eq "--help" || $ARGV[0] eq "-h")){
  usage();
  exit(0);
}

my $foundFiles = 0;
my $getToStr = 0;
my $i = 0;
for($i=0; $i <= $#ARGV; ++$i){
  if(!$foundFiles){
    if($ARGV[$i] eq "--"){ $foundFiles = 1; }
    else{
      if($getToStr){ push @toStrs, $ARGV[$i]; $getToStr = 0; }
      else{ push @fromStrs, $ARGV[$i]; $getToStr = 1; }
    }
  }
  else{ push @inputFiles, $ARGV[$i]; }
}

if($#inputFiles < 0){ print "No input files listed.\n"; usage(); exit(1); }
if($#fromStrs < 0){ print "No replacements specified.\n"; usage(); exit(1); }
if($#fromStrs != $#toStrs){
  print "The number of from-strings does not match the number of " .
    "to-strings.\n";
  usage();
  exit(1);
}

for($i=0; $i <= $#inputFiles; ++$i){
  my ($base, $dir, $suffix) = fileparse($inputFiles[$i]);
  my $tmpFile = $dir . "." . $base . $suffix . "_" . time() . "_" . $$;
  while(-e $tmpFile){ $tmpFile = $tmpFile . int(rand(10)); }
  # In order to get the same access control, copy the original file to
  # the tmp file first
  runcmd("cp -a " . $inputFiles[$i] . " " . $tmpFile);
  if(open(RFH, $inputFiles[$i])){
    if($debug){ print "Opened " . $inputFiles[$i] . " for reading\n"; }
    if(open(WFH, "> " . $tmpFile)){
      if($debug){ print "Opened " . $inputFiles[$i] . " for writing\n"; }

      # Peform replacement in tmp file
      my $line;
      my $fileChanged = 0;
      while($line = <RFH>){
	my $j;
	for($j=0; $j <= $#fromStrs; ++$j){
	  $_ = $line;
	  if(s/$fromStrs[$j]/$toStrs[$j]/g){ $fileChanged = 1; }
	  $line = $_;
	}
	print WFH $line;
      }
      close WFH;
      close RFH;
      if($fileChanged){ print "Changed " . $inputFiles[$i] . "\n"; }

      # Remove original file
      runcmd("rm -f " . $inputFiles[$i]);

      # Mv tmp file to original
      runcmd("mv -f " . $tmpFile . " " . $inputFiles[$i]);
    }
    else{
      close RFH;
      print "Unable to open temporary file " . $tmpFile . "\n";
    }
  }
  else{ print "Unable to open " . $inputFiles[$i] . "\n"; }
}

sub runcmd{
  my ($cmd) = @_;
  if($debug){ print "CMD: " . $cmd . "\n"; }
  `$cmd`;
}

sub usage{
  print "replace --help |\n";
  print "replace -h |\n";
  print "replace from to [from to] ... -- file [file] ...\n";
}
